#include "drv_usb.h"

#define USB_ID                 0
#define OTG_CLOCK              CRM_OTGFS1_PERIPH_CLOCK
#define OTG_IRQ                OTGFS1_IRQn
#define OTG_IRQ_HANDLER        OTGFS1_IRQHandler
#define OTG_WKUP_EXINT_LINE    EXINT_LINE_18

#define OTG_PIN_GPIO           GPIOA
#define OTG_PIN_GPIO_CLOCK     CRM_GPIOA_PERIPH_CLOCK

#define OTG_PIN_DP             GPIO_PINS_12
#define OTG_PIN_DP_SOURCE      GPIO_PINS_SOURCE12

#define OTG_PIN_DM             GPIO_PINS_11
#define OTG_PIN_DM_SOURCE      GPIO_PINS_SOURCE11

#define OTG_PIN_VBUS           GPIO_PINS_9
#define OTG_PIN_VBUS_SOURCE    GPIO_PINS_SOURCE9

#define OTG_PIN_ID             GPIO_PINS_10
#define OTG_PIN_ID_SOURCE      GPIO_PINS_SOURCE10

#define OTG_PIN_SOF_GPIO       GPIOA
#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
#define OTG_PIN_SOF            GPIO_PINS_8
#define OTG_PIN_SOF_SOURCE     GPIO_PINS_SOURCE8

#define OTG_PIN_MUX            GPIO_MUX_3

#define USB_VBUS_IGNORE

void usb_gpio_config(void)
{
  gpio_init_type gpio_init_struct;

  crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
  gpio_default_para_init(&gpio_init_struct);

  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;


#ifdef USB_SOF_OUTPUT_ENABLE
  crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK, TRUE);
  gpio_init_struct.gpio_pins = OTG_PIN_SOF;
  gpio_init(OTG_PIN_SOF_GPIO, &gpio_init_struct);
  gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_SOF_SOURCE, OTG_PIN_MUX);
#endif

  /* otgfs use vbus pin */
#ifndef USB_VBUS_IGNORE
  gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
  gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
  gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX);
  gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
#endif
}

/**
  * @brief  usb 48M clock select
  * @param  clk_s:USB_CLK_HICK, USB_CLK_HEXT
  * @retval none
  */
void usb_clock48m_select(usb_clk48_s clk_s)
{
  if (clk_s == USB_CLK_HICK)
  {
    crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK);

    /* enable the acc calibration ready interrupt */
    crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK, TRUE);

    /* update the c1\c2\c3 value */
    acc_write_c1(7980);
    acc_write_c2(8000);
    acc_write_c3(8020);
    /* open acc calibration */
    acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE);
  }
  else
  {
    /* usb divider reset */
    crm_usb_div_reset();

    switch (system_core_clock)
    {
      /* 48MHz */
      case 48000000:
        crm_usb_clock_div_set(CRM_USB_DIV_1);
        break;

      /* 72MHz */
      case 72000000:
        crm_usb_clock_div_set(CRM_USB_DIV_1_5);
        break;

      /* 96MHz */
      case 96000000:
        crm_usb_clock_div_set(CRM_USB_DIV_2);
        break;

      default:
        break;
    }
  }
}

void usb_dc_low_level_init(uint8_t busid)
{
  usb_gpio_config();
  /* enable otgfs clock */
  crm_periph_clock_enable(OTG_CLOCK, TRUE);

  /* select usb 48m clcok source */
  usb_clock48m_select(USB_CLK_HEXT);

  /* enable otgfs irq */
  nvic_irq_enable(OTG_IRQ, 1, 0);
}

void usb_dc_low_level_deinit(uint8_t busid)
{
}

void OTGFS1_IRQHandler(void)
{
    extern void USBD_IRQHandler(uint8_t busid);
    USBD_IRQHandler(0);
}
